/**
 * Copyright 2010 Victor Egea Hernando
 *
 * RockScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 * 
 * RockScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with RockScript.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef ROUTINE_H_
#define ROUTINE_H_

#include "vmclass.h"
#include "method.h"
#include "vmtypes.h"

namespace paper{

enum stack_properties{
    // number of arguments + this | number of context registers
    SP_ARGUMENTS_THIS = 10, SP_CONTEXT_REGS = 2,
    // number of no-local registers
    SP_NO_LOCAL_EXP_REG = SP_ARGUMENTS_THIS + SP_CONTEXT_REGS
};

enum routine_flags{
    RFLG_JUMP = 0x01
};

enum routine_states{
    NEW, RUNNABLE, TERMINATED
};

/*
 *      ROUTINE STACK FRAME
 *     ----------------------
 *     |                    | 
 *     ----------------------                                     
 *     | method pointer     | ( <- Routine SP )                         -|  4 registers
 *     | program counter    |                                           -| CONTEXT_FRAME
 *     ---------------------- 
 *     | local reg 0        | ( <- SP )                                 -|
 *     | ...                | [ N registers ]                            |
 *     | local reg N-1      |                                            | 
 *     ----------------------                                            | 
 *     | exp reg M-1        |                    -|                      |
 *     | ...                | [ M registers ]     |                      | max: 2^15 registers
 * R10 | exp reg 0          | ( <- return )       |                      |     STACK_FRAME
 *     ----------------------                     | max : 2^8 registers  |
 * R09 | argument 9         |                     |  EXPRESSION_FRAME    |
 *     | ...                | [ 9 arguments ]     |                      |
 * R01 | argument 1         |                     |                      |
 * R00 | this               | ( <- this & EP )   -|                     -|
 *     ----------------------
 *     | ...                |
 *     ----------------------
 * 
 * >> the number of arguments in the stack frame is fixed to (10)
 * >> there are two kind of indexing methods:
 *     > expression-frame-indexing-method:
 *        * EP(i) = EP[i]
 *        - this is the fastest indexing approach
 *     > stack-frame-indexing-method:
 *        * SP(i) = SP[-(((STACK_FRAME_SIZE+i)%STACK_FRAME_SIZE)+1)], because C++ <-4%5=-4>
 *        - this allow us to access local-variables, arguments and expression registers
 *          without know the size of each frame as we are compiling, very useful when we
 *          are using a one-pass compiler without abstract-syntax-tree. They expand inwards.
 */

// some useful macros for compilers
#define REG_TOOGLE(idx) (-(idx+1)) // pointer-to-pointer conversion
#define REG_SP2EPQ(idx) (  idx<0 ) // is SP-to-EP-conversion possible?

// declared classes
class vmachine;
class paperlir;

class routine{

public:
    // routine stack: 64 Kbits
    static const corelib::uint32 ssize = PWRTWO(16);

public:
    // costructors & destructor
    routine( corelib::uint32 id );
    virtual ~routine();
    // main interface
    bool alloc_frame( method &method );
    void backtrace( std::ostream &os );
    void free_frame( void );

protected:
    // routine state
    corelib::uint32 _state;
    corelib::uint32 _flags;
    corelib::uint32 _lock;
    corelib::uint32 _pc;
    // routine id
    corelib::uint32 _id;
    // current method
    method *_mp;

    // HEAVY USE OF THIS!!
    corelib::uint32 _useful_sf;
    __register *_sp, *_ep;

    // stack
    __register *_stack;
    // stack pointer
    __register *_rsp;

    // friends
    friend class vmachine; 
    friend class paper2lir;

};

}; // namespace paper;

#endif // ROUTINE_H_
